#include "XLand.h"
#include "Event/Event.h"
#include "UI.h"
#include "include.h"
#include "ll/api/service/Bedrock.h"
#include "mc/math/Vec3.h"
#include "mc/world/level/BlockPos.h"
#include <utility>

using namespace XUtils;
// 全局变量
ll::event::ListenerPtr playerJoinEventListener;    //加入游戏
ll::event::ListenerPtr playerLeaveEventListener;   //离开游戏
ll::event::ListenerPtr playerDestroyBlockListener; //破坏方块
ll::event::ListenerPtr playerUseItemOnListener;    //对方块使用物品
ll::event::ListenerPtr playerUseItemListener;      //使用物品
ll::event::ListenerPtr playerInteractEntityEvent;  //与实体交互
ll::event::ListenerPtr pistonPushEvent;            //活塞推动
ll::event::ListenerPtr explodeEvent;               //爆炸事件
ll::event::ListenerPtr liquidFlowEvent;            //流动事件
ll::schedule::GameTickAsyncScheduler timeTask;     //定时计划   
mutex       LLmutex;                               //同步锁
const auto oneDayMilliseconds = 86400000;
extern Config config;
const auto cmdOpenLandMainUI = [](CommandOrigin const& origin, CommandOutput& output, XLandCmd const& param, ::Command const& cmd) {
    auto* entity = origin.getEntity();
    if (entity == nullptr || !entity->isType(ActorType::Player)) {output.error("Only players can run Xland"); return;}
    auto player = static_cast<Player*>(entity); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
    UI::main(player);
};
const auto cmdSetPoint = [](CommandOrigin const& origin, CommandOutput& output, XLandCmd const& param, ::Command const& cmd) {
    auto* entity    = origin.getEntity();
    if (entity == nullptr || !entity->isType(ActorType::Player)) {output.error("Only players can run Xland"); return;}
    auto player     = static_cast<Player*>(entity); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
    auto playerDate = PlayerDate::getPlayerDate(player->getUuid());
    auto newLand    = (int) param.setPoint;
    auto langCode   = getPlayerLangCode(*player);
    switch (newLand) {
        case 1: case 2: {
            auto pos = origin.getExecutePosition(cmd.mVersion, param.pos);
            pos.x = (int)pos.x;
            pos.y = (int)pos.y;
            pos.z = (int)pos.z;
            switch (playerDate->setPt(pos, newLand)) {
                case 2: output.success(papilio::format(i18n.get("set_point_1", langCode), playerDate->occupyPt1.toString(), config.occupyMode)); break;
                case 3: output.success(papilio::format(i18n.get("set_point_2", langCode), playerDate->occupyPt2.toString(), config.occupyMode)); break;
                case 5: output.success(papilio::format(i18n.get("set_point_3", langCode), playerDate->landpos.toString()  , config.occupyMode)); break;
                case 1: output.success(papilio::format(i18n.get("vicinity_have_land", langCode))); break;
                case 4: output.success(papilio::format(i18n.get("on_in_land", langCode)));         break;
                default: output.error(i18n.get("unknow_error", langCode));
            }
            break;
        }
        case 0: case 3: case 4:
            output.success(i18n.get(playerDate->reOccpyMode()? "open_occupy":"close_occupy", langCode));  //刷新占领模式
            break;
        default :
            output.error(i18n.get("unknow_error", langCode));
            break;
    }
    return;
};
const auto cmdBuyLand = [](CommandOrigin const& origin, CommandOutput& output, XLandCmd const& param, ::Command const& cmd) {
    //确认购买，待完善
    auto* entity  = origin.getEntity();
    if (entity == nullptr || !entity->isType(ActorType::Player)) {output.error("Only players can run Xland"); return;}
    auto player   = static_cast<Player*>(entity); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
    auto langCode = getPlayerLangCode(*player);
    auto lands    = XLand::getLand(*player, false);
    auto uuid     = player->getUuid();
    if(!(lands.empty()))    {output.error(i18n.get("have_citizenship", langCode)); return;}
    if(XLand::isDebt(uuid)) {output.error(i18n.get("have_debt",        langCode)); return;}
    auto name       = asString(XLand::playerNameDb->get(uuid.asString()));
    auto playerDate = PlayerDate::getPlayerDate(uuid);
    XLand land(playerDate->occupyPt1, playerDate->occupyPt2, playerDate->landpos, uuid, fmt::format("{} 的领土",name));
    auto xuid   = player->getXuid();
    auto reduce = 30 * land.area * config.ratioArea;
    REDUCE_MONEY(reduce) output.error(papilio::format(i18n.get("balance_warning", langCode), reduce)); REDUCE_MONEY_END(reduce)
    land.balance = reduce;

    if(playerDate->isOccupying) playerDate->reOccpyMode(); //关闭占领模式
    switch (land.addLand()) {
        case 0: 
            output.success(i18n.get("create_land_success", langCode));
            playerDate->occupyPt1 = 0;
            playerDate->occupyPt2 = 0;
            break;
        case 1: output.error(i18n.get("db_no_init"        , langCode)); break;
        case 3: output.error(i18n.get("vicinity_have_land", langCode)); break;
        case 5: output.error(i18n.get("need_set_point"    , langCode)); break;
        case 6: output.error(i18n.get("land_num_max"      , langCode)); break;
        default:output.error(i18n.get("unknow_error"      , langCode)); break;
    }
};
const auto cmdListLand = [](CommandOrigin const& origin, CommandOutput& output, XLandCmd const& param, ::Command const& cmd) {
    auto* entity  = origin.getEntity();
    if (entity == nullptr || !entity->isType(ActorType::Player)) {output.error("Only players can run Xland"); return;}
    auto player   = static_cast<Player*>(entity); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
    auto pls      = param.player.results(origin);
    auto uuid     = player->getUuid();
    auto langCode = getPlayerLangCode(*player);
    if(pls.empty()) { 
        output.success(XLand::listLandStr(player));
        return; 
    }

    if(player->getPlayerPermissionLevel() < PlayerPermissionLevel::Operator) {output.error(i18n.get("no_admin", langCode)); return;}
    for(auto pl : pls) {
        auto textRaw = TextPacket::createRawMessage(fmt::format("{} \n",XLand::listLandStr(pl)));
        player->sendNetworkPacket(textRaw);
    }
};
const auto cmdRemoveLand = [](CommandOrigin const& origin, CommandOutput& output, XLandCmd const& param, ::Command const& cmd) {
    auto* entity  = origin.getEntity();
    if (entity == nullptr || !entity->isType(ActorType::Player)) {output.error("Only players can run Xland"); return;}
    auto player   = static_cast<Player*>(entity); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
    auto langCode = getPlayerLangCode(*player);
    auto uuid = player->getUuid();
    auto landId = param.landId;
    switch (XLand::removeLand(landId, uuid)) {
        case  0: output.success(i18n.get("remove_land_success", langCode)); break;
        case  1: output.success(i18n.get("no_owner"           , langCode)); break;
        case  2: output.success(i18n.get("remove_land_failure", langCode)); break;
        default: output.error(i18n.get("unknow_error", langCode));
    }
    return;
};
const auto cmdTpLand = [](CommandOrigin const& origin, CommandOutput& output, XLandCmd const& param, ::Command const& cmd) {
    auto* entity = origin.getEntity();
    if (entity == nullptr || !entity->isType(ActorType::Player)) {output.error("Only players can run"); return;}
    auto player   = static_cast<Player*>(entity); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
    UI::listLand(*player, 2);
    return;
};
const auto cmdSetDefaultPerm = [](CommandOrigin const& origin, CommandOutput& output, XLandCmd const& param, ::Command const& cmd) {
    auto* entity  = origin.getEntity();
    if (entity == nullptr || !entity->isType(ActorType::Player)) {output.error("Only players can run Xland"); return;}
    auto player   = static_cast<Player*>(entity); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
    auto langCode = getPlayerLangCode(*player);
    auto landId = param.landId;
    if(!XLand::isOwner(landId,player->getUuid())) {
        output.error(i18n.get("no_admin", langCode));
        return;
    }
    auto json = nlohmann::json::parse(param.json.toStyledString());
    if( json.contains("ID"   )  || 
        json.contains("LID"  )  || 
        json.contains("user" )  || 
        json.contains("owner")  || 
        json.contains("minPt")  || 
        json.contains("maxPt")  ||
        json.contains("balance")||
        json.contains("isAtWar")) 
    { output.error(i18n.get("have_sensitive", langCode)); return;}
    int retu = 4;
    switch (param.setLand) {
        case SetLand::perm: retu = XLand::setLand(landId, json);                           break; //设置领地默认权限
        case SetLand::land: retu = XLand::setLand(landId, json, player->getUuid(), false); break; //设置领地信息
    }
    switch (retu) {
        case  0: output.success(i18n.get("set_land_success", langCode)); break;
        case  1: output.success(i18n.get("owner_set_land"  , langCode)); break;
        case  2: output.success(i18n.get("get_perm_failure", langCode)); break;
        case  3: output.success(i18n.get("get_land_failure", langCode)); break;
        default: output.success(i18n.get("unknow_error"    , langCode)); break;
    }
    
};
const auto cmdSetPlayerPerm = [](CommandOrigin const& origin, CommandOutput& output, XLandCmd const& param, ::Command const& cmd) {
    auto* entity  = origin.getEntity();
    if (entity == nullptr || !entity->isType(ActorType::Player)) {output.error("Only players can run Xland"); return;}
    auto player   = static_cast<Player*>(entity); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
    auto langCode = getPlayerLangCode(*player);
    auto landId = param.landId;
    if(!XLand::isOwner(landId,player->getUuid())) {
        output.error(i18n.get("no_admin", langCode));
        return;
    }

    auto pls = param.player.results(origin);
    if(pls.empty()) {
        output.error(i18n.get("no_find_player", langCode));
        return;
    }

    auto json = nlohmann::json::parse(param.json.toStyledString());
    for(auto pl : pls) {
        auto textRaw = TextPacket::createRawMessage(fmt::format("{} - {} \n",XLand::setLand(landId, json),pl->getName()));
        player->sendNetworkPacket(textRaw);
    }
};

//class XUtils
void XUtils::regEvent() {
    auto& eventBus = ll::event::EventBus::getInstance();
    XD::Event::playerInteractEntityEvent();
    XD::Event::pistonPushEvent();
    XD::Event::explodeEvent();
    XD::Event::liquidFlowEvent();
    playerJoinEventListener  = eventBus.emplaceListener<ll::event::PlayerJoinEvent>([](ll::event::PlayerJoinEvent& event){
        auto player = &event.self();
        auto uuid =  player->getUuid();
        PlayerDate::playerDate[uuid] = new PlayerDate();              //添加玩家数据索引
        XLand::playerNameDb->set(uuid.asString(), player->getName()); //记录玩家名称数据
        return true;
    });
    playerLeaveEventListener =  eventBus.emplaceListener<ll::event::PlayerLeaveEvent>([](ll::event::PlayerLeaveEvent& event){
        auto player = &event.self();
        auto uuid =  player->getUuid();
        delete PlayerDate::playerDate[uuid]; //释放内存
        PlayerDate::playerDate.erase(uuid) ; //移除玩家数据索引
        return true;
    });
    playerDestroyBlockListener = eventBus.emplaceListener<ll::event::PlayerDestroyBlockEvent>([](ll::event::PlayerDestroyBlockEvent& event){
        auto player = &event.self();
        auto blockPos = event.pos();
        auto uuid = player->getUuid();
        XLand* land;
        auto isInLand =  XLand::isInLand(blockPos,land);
        
        //=========================================== 领地事件拦截 ===========================================//
        ISINTERCEPT

        auto playerLandPerm = LandPerm(land->id, uuid);
        
        if (!playerLandPerm.destroyBlock) {
            event.cancel();
            logger.info("[DestroyBlock] 玩家 {} 尝试在 {} 处破坏方块 被拦截", player->getName(), blockPos.toString());
        }
        return true;
    });
    playerUseItemListener = eventBus.emplaceListener<ll::event::PlayerUseItemEvent>([](ll::event::PlayerUseItemEvent & event){
        auto player = &event.self();
        auto itemStack = &event.item();
        XLand* land;
        auto isInLand =  XLand::isInLand(player->getHeadPos(),land);
        auto uuid =  player->getUuid();
        //=========================================== 领地事件拦截 ===========================================//
        ISINTERCEPT
        auto playerLandPerm = LandPerm(land->id, uuid);
        if(itemStack->isDamageableItem()) { // 使用可消耗物品 （手上的）
            auto useItems = playerLandPerm.useItems;
            if(find_if(useItems.begin(), useItems.end(), [&itemStack](string& str){
                    return itemStack->getTypeName().find(str) != string::npos; 
                }) == useItems.end()) {
                event.cancel();
                logger.info("[UseItem] 玩家 {} 尝试使用物品: {} 被拦截", player->getName(), itemStack->getTypeName());
            }
        }
        return true;
    });
    playerUseItemOnListener = eventBus.emplaceListener<ll::event::PlayerUseItemOnEvent>([](ll::event::PlayerUseItemOnEvent& event){
        static BlockPos lastPt;
        auto player = &event.self();
        auto itemStack = &event.item();
        auto blockPos = event.blockPos();
        XLand* land;
        auto isInLand =  XLand::isInLand(blockPos,land);

        auto uuid =  player->getUuid();
        auto playerDate = PlayerDate::getPlayerDate(uuid);
        auto langCode   = getPlayerLangCode(*player);
        //=========================================== 领地占领模式 ===========================================//
        if (playerDate->isOccupying && itemStack->getRawNameId() == config.occupyItem){
            if(lastPt == blockPos) return true; lastPt = blockPos; //禁用连续读点
            string textRaw;
            switch (playerDate->setPt(blockPos, 0)) {
                case 2:  textRaw = papilio::format(i18n.get("set_point_1", langCode), playerDate->occupyPt1.toString(), config.occupyMode); break;
                case 3:  textRaw = papilio::format(i18n.get("set_point_2", langCode), playerDate->occupyPt2.toString(), config.occupyMode); break;
                case 5:  textRaw = papilio::format(i18n.get("set_point_3", langCode), playerDate->landpos  .toString(), config.occupyMode); break;
                case 1:  textRaw = papilio::format(i18n.get("vicinity_have_land", langCode)); break;
                case 4:  textRaw = papilio::format(i18n.get("on_in_land", langCode));         break;
                default: textRaw = i18n.get("unknow_error", langCode);
            }
            TextPacket::createRawMessage(textRaw).sendTo(*player);
            return false;
        }
        //=========================================== 领地事件拦截 ===========================================//
        ISINTERCEPT

        auto block = event.block();
        auto playerLandPerm = LandPerm(land->id, uuid);
        
        if(block->isInteractiveBlock()){ // 使用可交互方块 （地上的）
            auto useBlocks = playerLandPerm.useBlocks;
            if(useBlocks.empty() || (*useBlocks.begin() != "all" && find_if(useBlocks.begin(),useBlocks.end(),[&block](string& str){
                    return block->getTypeName().find(str) != string::npos; 
                }) == useBlocks.end())) {
                event.cancel();
                logger.info("[UseBlock] 玩家 {} 尝试操作方块: {} 被拦截", player->getName(), block->getTypeName());
            }
        }
        else if(itemStack->isBlock() || itemStack->getTypeName() == "minecraft:wooden_door") {  // 放置方块
            if (!playerLandPerm.placeBlock) {
                event.cancel();
                if(lastPt != blockPos) logger.info("[PlaceBlock] 玩家 {} 尝试在 {} 处放置方块: {} 被拦截", player->getName(), blockPos.toString(), itemStack->getTypeName());
                lastPt = blockPos;
            }
        }
        else {                          // 使用物品 （手上的）
            auto useItems = playerLandPerm.useItems;
            if(useItems.empty() || (*useItems.begin() != "all" && find_if(useItems.begin(), useItems.end(), [&itemStack](string& str){
                    return itemStack->getTypeName().find(str) != string::npos; 
                }) == useItems.end())) {
                event.cancel();
                logger.info("[UseItem] 玩家 {} 尝试使用物品: {} 被拦截", player->getName(), itemStack->getTypeName());
            }
        }
        return true;
    });
    playerInteractEntityEvent = eventBus.emplaceListener<XD::Event::PlayerInteractEntityEvent>([](XD::Event::PlayerInteractEntityEvent& event){
        auto entity = event.mEntity;
        auto player = &event.self();
        auto uuid =  player->getUuid();
        auto pos = entity->getHeadPos();
        XLand* land;
        auto isInLand = XLand::isInLand(pos,land);
        //=========================================== 领地事件拦截 ===========================================//
        ISINTERCEPT

        auto playerLandPerm = LandPerm(land->id, uuid);
        auto useEntitys = playerLandPerm.useEntitys;

        if(useEntitys.empty() || (*useEntitys.begin() != "all" && find_if(useEntitys.begin(),useEntitys.end(),[&entity](string& str){
                return entity->getTypeName().find(str) != string::npos; 
            }) == useEntitys.end())) {
            event.cancel();
            logger.info("[UseEntity] 玩家 {} 尝试与实体 {} 互动，被拦截", player->getName(), entity->getTypeName());
        }
        return true;
    });
    pistonPushEvent = eventBus.emplaceListener<XD::Event::PistonPushEvent>([](XD::Event::PistonPushEvent& event){
        auto    pos = event.curPos;
        XLand* land;
        auto isINLand = XLand::isInLand(pos,land);
        //=========================================== 领地事件拦截 ===========================================//
        if(!isINLand || land->pistonPush) return true;
        logger.info("[PistonPush] 活塞在 {} 处推动被拦截", pos.toString());
        event.cancel();
        return true;
    });
    explodeEvent = eventBus.emplaceListener<XD::Event::ExplodeEvent>([](XD::Event::ExplodeEvent& event){
        auto pos = event.pos;
        auto r   = event.explosionRadius;
        XLand* land;
        auto isINLand = XLand::hasLandIntersection(pos + r, pos - r, land);
        //=========================================== 领地事件拦截 ===========================================//
        if(!isINLand || land->explode) return true;
        logger.info("[Explode] {} 处发生爆炸被拦截", pos.toString());
        event.cancel();
        return true;
    });
    liquidFlowEvent = eventBus.emplaceListener<XD::Event::LiquidFlowEvent>([](XD::Event::LiquidFlowEvent& event) {
        auto pos = event.flowFromPos;
        auto to  = event.pos;
        XLand* land;
        auto isINLand = XLand::isInLand(to,land);
        //=========================================== 领地事件拦截 ===========================================//
        if(!isINLand || land->liquidFlow) return true;
        logger.info("[LiquidFlow] 液体 {} -> {} 流动被拦截", pos.toString(), to.toString());
        event.cancel();
        return true;
    });
}
void XUtils::removeEvent() {
    auto& eventBus = ll::event::EventBus::getInstance();
    eventBus.removeListener(playerJoinEventListener);
    eventBus.removeListener(playerLeaveEventListener);
    eventBus.removeListener(playerDestroyBlockListener);
    eventBus.removeListener(playerUseItemOnListener);
    eventBus.removeListener(playerInteractEntityEvent);
}
/*
* PS: -非必填 | ！管理员 | <>变参 |
* 
* xland start | stop                        // 开始占领模式 | 停止占领模式
* xland setPt1|setPt2    -<Vec3>            // 选择占领对角点
* xland buy                                 // 购买领地
* xland list  -!<player>                    // 列出自己的所有领地 | !列出相应玩家的所有领地
* xland remove  <landId>                    // 移除领地
* xland tp      <landId>                    // 传送到领地
* xland set     <landId>  <player> <json>   // 设置玩家在该领地的权限
* xland set     <landId>  <json>            // 设置领地默认权限
*/ 
void XUtils::regXLandCmd() {
    auto commandRegistry = ll::service::getCommandRegistry();
    if (!commandRegistry) throw std::runtime_error("failed to get command registry"); //获取命令注册表失败
    auto& cmd = ll::command::CommandRegistrar::getInstance().getOrCreateCommand("xland", "领地系统", CommandPermissionLevel::Any);
    cmd.overload<XLandCmd>().execute<cmdOpenLandMainUI>();
    cmd.overload<XLandCmd>().text("gui").execute<cmdOpenLandMainUI>();
    cmd.overload<XLandCmd>().required("setPoint").execute<cmdSetPoint>();
    cmd.overload<XLandCmd>().required("setPoint").required("pos").execute<cmdSetPoint>();
    cmd.overload<XLandCmd>().text("buy").execute<cmdBuyLand>();
    cmd.overload<XLandCmd>().text("list").execute<cmdListLand>();
    cmd.overload<XLandCmd>().text("list").required("player").execute<cmdListLand>();
    cmd.overload<XLandCmd>().text("remove").required("landId").execute<cmdRemoveLand>();
    cmd.overload<XLandCmd>().text("tp").execute<cmdTpLand>();
    cmd.overload<XLandCmd>().text("set").required("setLand").required("landId").required("json").execute<cmdSetDefaultPerm>();
    cmd.overload<XLandCmd>().text("set").required("landId").required("player").required("json").execute<cmdSetPlayerPerm>();
}
void XUtils::newTaskAll() {
    timeTask.add<ll::schedule::RepeatTask>(
        chrono::milliseconds(config.loop),
        [](){
            lock_guard<mutex> lock(LLmutex);
            ll::service::getLevel()->forEachPlayer([](Player& player){
                auto playerDate = PlayerDate::getPlayerDate(player.getUuid());
                if(!playerDate) return true;

                XLand* land = nullptr;
                auto playerPos = player.getHeadPos();
                auto isInLand  = XLand::isInLand(playerPos, land);
                auto langCode  = getPlayerLangCode(player);
                if(land) {
                    // auto gmpl = (GMLIB_Player*) &player;
                    if(isInLand) { 
                        // 进入领地时
                        if(land->pENTERLand && !(playerDate->isInLand)){ 
                            TextPacket::createRawMessage(papilio::format(i18n.get("enter_land_prompt", langCode), land->getLandName())).sendTo(player);
                            // 这里使用particleCUI会发送错误的包
                            // auto pt1 = land->minPt;
                            // auto pt2 = land->maxPt + 1;
                            // pt2.y = pt1.y = (int)playerPos.y;
                            // particleCUI.drawCuboid(AABB(pt1, pt2),0,ParticleCUI::ColorPalette::GREEN);
                        }
                    } else {
                        // 离开领地时
                        TextPacket::createRawMessage(papilio::format(i18n.get("exit_land_prompt", langCode))).sendTo(player);
                    }
                }
                playerDate->isInLand = isInLand;
                return true;
    });});
}

//class XLand
bool                 XLand::isInitDB                 = false;
XLand::Node*         XLand::rootNode                 = nullptr;
vector<XLand>        XLand::landList                 = {};
vector<XLand::Node*> XLand::nodeVector               = {};
XLand*               XLand::default_land             = nullptr;
unique_ptr<SQLite::Database> XLand::db               = nullptr;
unique_ptr<ll::data::KeyValueDB> XLand::playerNameDb = nullptr;

//private
XLand::Node* XLand::build(const vector<XLand>::iterator& begin, const vector<XLand>::iterator& end, int depth) {
    if (begin == end) return nullptr;
    int axis = depth % 3;
    auto median_it = begin + (end - begin) / 2;
    nth_element(begin, median_it, end, [axis](const XLand a, const XLand b) {
        switch (axis) {
            case 0: return a.minPt.x < b.minPt.x;
            case 1: return a.minPt.y < b.minPt.y;
            case 2: return a.minPt.z < b.minPt.z;
            default: return false;
        }
    });

    auto node  = new Node{&*median_it,nullptr, nullptr};
    nodeVector.push_back(node); //保存指针，需要时清空
    node->left  = build(begin, median_it, depth + 1);
    node->right = build(median_it+1, end, depth + 1);
    
    return node;
}
bool XLand::contains(Node* node, const Vec3& point, XLand*& land = default_land, int depth = 0) {
    if (node == nullptr) return false;
    int axis = depth % 3;
    bool isInLand = point.x <= node->land->maxPt.x && point.x >= node->land->minPt.x &&
                    point.y <= node->land->maxPt.y && point.y >= node->land->minPt.y &&
                    point.z <= node->land->maxPt.z && point.z >= node->land->minPt.z ;
    if(isInLand) {
        land = node->land;
        land->renew(); // 刷新数据
        return true;
    }
    bool goLeft = false;
    bool goRight = false;
    switch (axis) {
        case 0: 
        if      (node->right!=nullptr && point.x > node->right->land->minPt.x) goRight = true; 
        else if (node->left !=nullptr && point.x < node->left ->land->maxPt.x) goLeft  = true;
        break;
        case 1: 
        if      (node->right!=nullptr && point.y > node->right->land->minPt.y) goRight = true;
        else if (node->left !=nullptr && point.y < node->left ->land->maxPt.y) goLeft  = true;
        break;
        case 2: 
        if      (node->right!=nullptr && point.z > node->right->land->minPt.z) goRight = true;
        else if (node->left !=nullptr && point.z < node->left ->land->maxPt.z) goLeft  = true;
        break;
    }
    if     (goLeft ) return contains(node->left , point, land, depth + 1) ;
    else if(goRight) return contains(node->right, point, land, depth + 1) ;
    else             return contains(node->left , point, land, depth + 1)|| 
    /*return ============*/ contains(node->right, point, land, depth + 1) ;
}
bool XLand::searchRange(Node* node, const Vec3& minPt, const Vec3& maxPt, XLand*& land = default_land, int depth = 0) {
    if (node == nullptr) return false;
    int axis = depth % 3;
    bool withinRange = minPt.x <= node->land->maxPt.x && maxPt.x >= node->land->minPt.x &&
                       minPt.y <= node->land->maxPt.y && maxPt.y >= node->land->minPt.y &&
                       minPt.z <= node->land->maxPt.z && maxPt.z >= node->land->minPt.z ;
    //==============搜索成功===============//
    if (withinRange)  {                   //
        land = node->land;                //
        return true;                      //
    }                                     //
    //==============搜索成功===============//
    bool goLeft = false;
    bool goRight = false;
    switch (axis) {
        case 0: 
        if     (node->right!=nullptr && maxPt.x > node->right->land->minPt.x) goRight = true;
        else if(node->left !=nullptr && minPt.x < node->left ->land->maxPt.x) goLeft  = true;
        break;
        case 1: 
        if     (node->right!=nullptr && maxPt.y > node->right->land->minPt.y) goRight = true;
        else if(node->left !=nullptr && minPt.y < node->left ->land->maxPt.y) goLeft  = true;
        break;
        case 2: 
        if     (node->right!=nullptr && maxPt.z > node->right->land->minPt.z) goRight = true;
        else if(node->left !=nullptr && minPt.z < node->left ->land->maxPt.z) goLeft  = true;
        break;
    }
    if     (goLeft ) return searchRange(node->left , minPt, maxPt, land, depth + 1) ;
    else if(goRight) return searchRange(node->right, minPt, maxPt, land, depth + 1) ;
    else             return searchRange(node->left , minPt, maxPt, land, depth + 1)|| 
    /*return ============*/ searchRange(node->right, minPt, maxPt, land, depth + 1) ;
}
// 我认为搜索算法还能优化，但是我失败了！ 希望大佬们能进一步优化
// bool XLand::contains(Node* node, const Vec3& point, XLand*& land = default_land, int depth = 0) {
//     if (!node) return false;
//     int axis = 0;
//     if      (point.x > node->land->maxPt.x) axis += 1;
//     else if (point.x < node->land->minPt.x) axis += 2;
//     if      (point.y > node->land->maxPt.y) axis += 3;
//     else if (point.y < node->land->minPt.y) axis += 4;
//     if      (point.z > node->land->maxPt.z) axis += 5;
//     else if (point.z < node->land->minPt.z) axis += 6;
//     switch (axis) {
//         case 0: 
//             cout << "inLand" << endl;
//             land = node->land;
//             return true;
//         case 1: case 3: case 5: case 9:
//             return contains(node->left, point, land, depth);
//         case 2: case 4: case 6: case 12:
//             return contains(node->right, point, land, depth);
//         default: 
//             return contains(node->left, point, land, depth) || contains(node->right, point, land, depth);
//     }
// }

void XLand::clearNodeVector() {
    for(auto& node : nodeVector) delete node;
    nodeVector.clear();
}
XLand::XLand(long id, string name, mce::UUID owner, Vec3 minPt, Vec3 maxPt, long balance = 0) {
    this->id      = id;
    this->name    = name;
    this->owner   = owner;
    this->minPt   = minPt;
    this->maxPt   = maxPt;
    auto s = maxPt - minPt;
    this->area    = s.x * s.z;
    this->balance = balance;
}

//public
bool XLand::initDB() {
    try {  //尝试创建文件夹
        filesystem::create_directories(config.DBPath);
    } catch (const filesystem::filesystem_error& e) {cerr << "创建必要文件夹失败" << e.what(); return false;}
    try {
        playerNameDb = make_unique<ll::data::KeyValueDB>(config.DBPath + "player");
        db           = make_unique<SQLite::Database>(config.DBPath + "Xland.db", SQLite::OPEN_CREATE | SQLite::OPEN_READWRITE);
        db->exec(R"(CREATE TABLE IF NOT EXISTS land (
            ID INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT DEFAULT '',
            owner TEXT,
            minPt TEXT,
            maxPt TEXT,
            area INTEGER,
            teleport TEXT DEFAULT '0,0,0',
            pENTERLand BOOLEAN DEFAULT true,

            pistonPush BOOLEAN DEFAULT false,
            explode BOOLEAN DEFAULT false,
            liquidFlow BOOLEAN DEFAULT false,

            balance INTEGER DEFAULT 0
        ))");
        db->exec(R"(CREATE TABLE IF NOT EXISTS perm (
            ID INTEGER PRIMARY KEY AUTOINCREMENT,
            LID INTEGER,
            user TEXT DEFAULT 0,
            pickUpItem BOOLEAN DEFAULT true,
            playerAttac BOOLEAN DEFAULT false,
            destroyBlock BOOLEAN DEFAULT false,
            placeBlock BOOLEAN DEFAULT false,
            useItems TEXT,
            useBlocks TEXT,
            useEntitys TEXT
        ))");
        db->exec(R"(CREATE TABLE IF NOT EXISTS mess (
            ID INTEGER PRIMARY KEY AUTOINCREMENT,
            form TEXT,
            `to` INTEGER,
            type INTEGER DEFAULT 0,
            title TEXT,
            content TEXT,
            money INTEGER DEFAULT 0,
            status INTEGER DEFAULT 0
        ))");
        SQLite::Statement get{*db,"SELECT * FROM PRAGMA_TABLE_INFO('land') WHERE name IN ('pistonPush');"};
        if (!get.executeStep()) {
            db->exec("ALTER TABLE land ADD pistonPush BOOLEAN DEFAULT false");
            db->exec("ALTER TABLE land ADD explode BOOLEAN DEFAULT false");
            db->exec("ALTER TABLE land ADD liquidFlow BOOLEAN DEFAULT false");
        }
        get.clearBindings();

    } catch (std::exception const &e) {cerr << "初始化数据库失败: " << e.what() << endl; return false;}
    isInitDB = true;
    return isInitDB;
}
void XLand::buildLand() {
    if(!nodeVector.empty()) return;
    string sql = "SELECT ID FROM land";
    try {
        SQLite::Statement get{*db,sql};
        landList.clear(); //重置领地列表
        while (get.executeStep()) {
            long id = get.getColumn("ID").getInt64();
            landList.push_back(XLand(id));
        }
        get.clearBindings();
    } catch (std::exception const &e) {cerr << "领地索引构建失败: " << e.what() << endl; return;}
    rootNode = build(landList.begin(),landList.end(),0);
}
bool XLand::isInLand(const Vec3& point, XLand*& land = default_land) {
    return contains(rootNode, point, land);
}
bool XLand::hasLandIntersection(const Vec3& pt1, const Vec3& pt2, XLand*& land = default_land) {
    auto max = pt1;
    auto min = pt2;
    XUtils::toMaxMin(max, min);
    return searchRange(rootNode, min, max, land);
}
shared_ptr<vector<XLand>> XLand::listLand(const mce::UUID& uuid) {
    auto where = uuid == 0 ? "" : fmt::format("WHERE owner = '{}'", uuid.asString());
    auto sql   = fmt::format("SELECT ID FROM land {}", where);
    auto temp  = make_shared<vector<XLand>>();
    try {
        SQLite::Statement get{*db,sql};
        while (get.executeStep()) temp->push_back(XLand(get.getColumn(0).getInt64()));
        get.clearBindings();
    } catch (std::exception const &e) {cerr << "error: " << e.what() << endl; return nullptr;}
    return temp;
}
string XLand::listLandStr(const Player* player) {
    auto uuid = player->getUuid().asString();
    string put =  fmt::format("------ {} ------ \n", player->getName());
    auto lands = listLand(uuid);
    for(const auto& land : *lands) put += fmt::format("ID: {} | name: {} \n",land.id, land.name);
    return put;
}
shared_ptr<vector<XLand>> XLand::searchLand(const string& key) {
    string sql = fmt::format("SELECT * FROM land WHERE ID = '{}' OR name LIKE '{}'", key, key);
    auto temp  = make_shared<vector<XLand>>();
    try {
        SQLite::Statement get{*db,sql};
        while (get.executeStep()) {
            long      id    = get.getColumn(0).getInt64();
            string    name  = get.getColumn(1);
            mce::UUID owner = mce::UUID::fromString(get.getColumn(2));
            Vec3      minPt = stringToVec3(get.getColumn(3));
            Vec3      maxPt = stringToVec3(get.getColumn(4));
            temp->push_back(XLand(id,name,owner,minPt,maxPt));
        }
        get.clearBindings();
    } catch (std::exception const &e) {cerr << "error: " << e.what() << endl; return nullptr;}
    return temp;
}
bool XLand::isOwner(const long& landId,const mce::UUID& uuid) {
    string sql = fmt::format("SELECT * FROM land WHERE owner = '{}' AND ID = {}", uuid.asString(),landId);
    try {
        SQLite::Statement get{*db,sql};
        bool is = get.executeStep();
        get.clearBindings();
        return is;
    } catch (std::exception const &e) {cerr << "error: " << e.what() << endl; return false;}
}
bool XLand::isDebt(const mce::UUID& uuid) {
    try {
        SQLite::Statement get{*db,fmt::format("SELECT * FROM land WHERE owner = '{}' AND balance < -{}", uuid.asString(), config.maxDebt)};
        bool is = get.executeStep();
        get.clearBindings();
        return is;
    } catch (std::exception const &e) {cerr << "XLand::isDebt error: " << e.what() << endl; return false;}
}
/**
 * @return code
 * 0: 已移除领地
 * 1: 你不是领地主，无法移除领地
 * 2: 移除领地失败
 */
int XLand::removeLand(const long& landId,const mce::UUID& uuid) {
    XLand land(landId);
    if(land.owner != uuid) return 1;
    try { 
        db->exec(fmt::format("DELETE FROM perm WHERE LID = {}", landId)); //移除相关权限数据
        db->exec(fmt::format("DELETE FROM land WHERE ID = {}",  landId)); //移除领地数据
    } catch (std::exception const &e) {cerr << "error:" << e.what() << endl; return 2;}
    auto dif = land.maxPt-land.minPt;
    auto s = dif.x * dif.y * dif.z; //领地面积（用于计算回收价格）
    clearNodeVector();              //释放领地节点内存
    buildLand();                    //重新构建领地k-d树
    return 0;
}
/**
 * @return code
 * 0: 设置领地成功
 * 1: 主人家不用限制自己啦！
 * 2: 获取权限表失败
 * 3: 获取领地数据失败
 * 4：未知错误
 */
int XLand::setLand(const long& landId,const nlohmann::json& json, const mce::UUID& uuid, bool setPerm) {
    if(setPerm && isOwner(landId, uuid)) return 1;
    bool isOnDate = false;
    long Id;
    string sql; //生成SQL
    try { 
        sql = setPerm ? fmt::format("SELECT * FROM perm WHERE LID = {} AND (user = '{}' OR user = 0) ORDER BY user DESC",landId,uuid.asString()) :
                        fmt::format("SELECT * FROM land WHERE ID  = {} AND owner = '{}'",landId,uuid.asString());
        SQLite::Statement get{*XLand::db,sql};
        if (get.executeStep()) {
            isOnDate = true;
            Id = get.getColumn(0).getInt64();
        }
        get.clearBindings();
    } catch (std::exception const &e) {cerr << "获取权限表失败: " << e.what() << endl; return 2;}
    try {
        if(isOnDate) {
            string set;
            for(const auto& item : json.items()) {
                auto key   = item.key()  ;
                auto value = item.value();
                // cout << fmt::format("{} : {}", key, value.type_name());
                if      (value.is_boolean()) set += fmt::format("{} = {},"  , key, value.get<bool>()  );
                else if (value.is_number() ) set += fmt::format("{} = {},"  , key, value.get<long>()  );
                else if (value.is_string() ) set += fmt::format("{} = '{}',", key, value.get<string>());
                else continue;
            }
            set.pop_back();
            sql = setPerm ? fmt::format("UPDATE perm SET {} WHERE ID = {}",set,Id):
                            fmt::format("UPDATE land SET {} WHERE ID = {}",set,Id);
        } else if(!setPerm) {
            return 3;
        } else {
            string a("("),b("(");
                a += "LID," ; b += fmt::format("{},",landId);
                a += "user,"; b += fmt::format("{},",uuid.asString());
            for(const auto& item : json.items()) {
                auto value = item.value();
                a += fmt::format("{},",item.key());
                if(value.is_null()) continue;
                else if(value.is_boolean()) b += fmt::format("{},"  , value.get<bool>());
                else if(value.is_number() ) b += fmt::format("{},"  , value.get<long>());
                else if(value.is_string() ) b += fmt::format("'{}',", value.get<string>());
            }
            a.pop_back(); b.pop_back(); a.push_back(')'); b.push_back(')');
            sql = fmt::format("INSERT INTO perm {} VALUES {}",a,b);
        }
        // cout << sql << endl;
        SQLite::Statement set{*XLand::db, sql};
        set.exec();
        set.reset();
        set.clearBindings();
    } catch (std::exception const &e) { fmt::println("§cSQL语句错误：{}  error:{}", sql, e.what()); return 4;}
    return 0;
}

XLand::XLand(Vec3 pt1, Vec3 pt2, Vec3 teleport, mce::UUID owner, string name ="") {
    int minX,minY,minZ,maxX,maxY,maxZ;
    if (pt1.x < pt2.x) {minX = pt1.x; maxX = pt2.x;}
    else               {minX = pt2.x; maxX = pt1.x;}

    if (pt1.y < pt2.y) {minY = pt1.y; maxY = pt2.y;}
    else               {minY = pt2.y; maxY = pt1.y;}

    if (pt1.z < pt2.z) {minZ = pt1.z; maxZ = pt2.z;}
    else               {minZ = pt2.z; maxZ = pt1.z;}
    minPt = Vec3(minX,minY,minZ);
    maxPt = Vec3(maxX,maxY,maxZ);
    auto s = maxPt - minPt;
    this->name  = name ;
    this->owner = owner;
    this->area  = s.x * s.z;
    this->teleport = teleport;
}
XLand::XLand(const long& landId) {
    this->id = landId;
    this->renew();
}
void XLand::renew() {
    try {
        SQLite::Statement get{*db,fmt::format("SELECT * FROM land WHERE ID = {}",this->id)};
        if (get.executeStep()) {
            this->id         = get.getColumn("ID").getInt64();
            this->name       = get.getColumn("name").getString();
            this->owner      = mce::UUID::fromString(get.getColumn("owner").getString());
            this->minPt      = stringToVec3(get.getColumn("minPt").getString());
            this->maxPt      = stringToVec3(get.getColumn("maxPt").getString());
            this->area       = get.getColumn("area").getInt64();
            this->teleport   = stringToVec3(get.getColumn("teleport").getString());
            this->pENTERLand = get.getColumn("pENTERLand").getInt();
            this->pistonPush = get.getColumn("pistonPush").getInt();
            this->explode    = get.getColumn("explode").getInt();
            this->liquidFlow = get.getColumn("liquidFlow").getInt();
            this->balance    = get.getColumn("balance").getInt64();
        }
        get.clearBindings();
    } catch (std::exception const &e) {cerr << "从数据库构建领地失败: " << e.what() << endl;}
}
bool XLand::isInThisLand(const Vec3& pos) {
    return minPt.x <= pos.x && pos.x < maxPt.x && minPt.z <= pos.z && pos.z < maxPt.z && minPt.y <= pos.y && pos.y < maxPt.y;
}
bool XLand::isInThisLand(Player* pl) {
    return this->isInLand(pl->getFeetPos());
}
/**
* @return code
* 0：成功
* 1: 数据库未初始化
* 2: 领地不是用户构建的
* 3：与其他领地有交集 或 附近有其他领地
* 4: 领地数据添加失败，详细请看控制台
* 5: 未完成领地的选择
* 6: 领地数已达到最大
**/
int XLand::addLand() {
    if (!isInitDB)                                           return 1;
    if (id)                                                  return 2;
    if (minPt == 0 || maxPt == 0 || teleport == 0)           return 5;
    if (hasLandIntersection(minPt-10, maxPt+10))             return 3;
    if (getLand(this->owner,true).size()>=config.maxLandNum) return 6;
    
    if(config.occupyMode == "2D") {
        this->maxPt.y = 256;
        this->minPt.y = -10;
    }
    
    auto owner    = this->owner.asString();
    auto minPtStr = this->minPt.toString();
    auto maxPtStr = this->maxPt.toString();
    auto midPtStr = this->teleport.toString();
    auto minPt    = stringRemoveBE(minPtStr);
    auto maxPt    = stringRemoveBE(maxPtStr);
    auto midPt    = stringRemoveBE(midPtStr);

    try {
        db->exec(fmt::format("INSERT INTO land (name, owner, minPt, maxPt, area, balance, teleport, hp) VALUES ('{}','{}','{}','{}',{}, {}, '{}', {})",name,owner,minPt,maxPt,area,balance,midPt,balance));
    } catch (exception const &e) {cerr << "创建领地失败:" << e.what() << endl; return 4;}
    clearNodeVector();  //释放领地节点内存
    buildLand();        //重新构建领地数据
    return 0;
}
void XLand::tpLand(Player& player) const {
    cout << teleport.toString() << endl;
    XPacket::runCommand(fmt::format("spreadplayers {} {} 0 {} {}", teleport.x, teleport.z, config.tpLandRange, player.getRealName()));
}
int XLand::getDistance(const Player& player) {
    auto temp = player.getFeetPos() - teleport;
    temp = temp * temp;
    return sqrt(temp.x + temp.y + temp.z);
}
void XLand::shiftLand(const mce::UUID newOwner) {
    try {
        db->exec(fmt::format("UPDATE land SET owner = {} WHERE ID = {}",newOwner.asString(), this->id));
    } catch (std::exception const &e) {}
    this->owner = newOwner;
}
void XLand::reBorder(int dimId , enum ParticleCUI::ColorPalette color) {
    ParticleCUI particleCUI;
    particleCUI.drawCuboid(AABB(maxPt+1,minPt),dimId,color);
}
string XLand::getLandName() {
    return this->name;
}
string XLand::getOwnerName() {
    return asString(playerNameDb->get(owner.asString()));
}
nlohmann::json XLand::getJson() {
    nlohmann::json pack;
    // auto teleportStr   = teleport.toString();
    pack["name"]       = name;
    pack["pENTERLand"] = pENTERLand;
    pack["balance"]    = balance;
    pack["pistonPush"] = pistonPush;
    pack["explode"]    = explode;
    pack["liquidFlow"] = liquidFlow;
    return pack;
}
void XLand::charge() {
    try {
        db->exec(fmt::format("UPDATE land SET balance = balance - (area * {} + (SELECT COUNT(*) FROM mess WHERE type = 1 AND status = 2) * {}) WHERE balance > -{}", config.ratioArea, config.ratioPopulation, config.maxDebt));
    } catch (std::exception const &e) {}
}
bool XLand::formMess(const Mess& mess) {
    try {
        db->exec(fmt::format("INSERT INTO mess (form,`to`,type,title,content,money) VALUES ('{}',{},{},'{}','{}',{})", mess.form.asString(), mess.to, mess.type, mess.title, mess.content, mess.money));
    } catch (std::exception const &e) { cerr << "发送消息失败: " << e.what() << endl; return false;}
    return true;
}
bool XLand::upDateMess(const long& id, const int& status) {
    try {
        db->exec(fmt::format("UPDATE mess SET status={} WHERE ID={}", status, id));
    } catch (std::exception const &e) { cerr << "更新信息失败: " << e.what() << endl; return false;}
    return true;
}
long XLand::getLandId(const string& value) {
    string sql = fmt::format("SELECT ID FROM land WHERE ID = {} or name = '{}'", value, value);
    try {
        SQLite::Statement get{*db,sql};
        auto retu = get.executeStep() ? get.getColumn(0).getInt64() : 0;
        get.clearBindings();
        return retu;
    } catch (std::exception const &e) {cerr << "获取领地ID失败: " << e.what() << endl;}
    return 0;
}
vector<long> XLand::getLand(const mce::UUID& uuid, bool isOwner) {
    auto uid = uuid.asString();
    string sql = isOwner ? fmt::format("SELECT ID FROM land WHERE owner = '{}'", uid) :
                           fmt::format("SELECT `to` FROM mess WHERE type = 1 AND status = 2 AND form = '{}'", uid);
    vector<long> temp;
    try {
        SQLite::Statement get{*db,sql};
        while (get.executeStep()) temp.push_back(get.getColumn(0).getInt64());
        get.clearBindings();
    } catch (std::exception const &e) {cerr << "获取多领地ID失败: " << e.what() << endl;}
    return temp;
}
vector<long> XLand::getLand(const Player& player, bool isOwner) {
    return getLand(player.getUuid(), isOwner);
}
vector<XLand::Mess> XLand::getMess(const long& landId, string where) {
    vector<Mess> temp;
    try {
        SQLite::Statement get{*db,fmt::format("SELECT * FROM mess WHERE `to` = {} {}", landId, where)};
        while (get.executeStep()) {
            long      id      = get.getColumn("ID").getInt64();
            mce::UUID form    = get.getColumn("form").getString();
            int       type    = get.getColumn("type").getInt();
            string    title   = get.getColumn("title").getString();
            string    content = get.getColumn("content").getString();
            int       status  = get.getColumn("status").getInt();
            long long money   = get.getColumn("money").getInt64();
            temp.push_back(Mess(id,form,landId,type,title,content,status,money));
        }
        get.clearBindings();
    } catch (std::exception const &e) {cerr << "获取信息失败: " << e.what() << endl;}
    return temp;
}

//class LandPerm
LandPerm::LandPerm() {
    perm["playerAttac"]  = &playerAttac;
    perm["destroyBlock"] = &destroyBlock;
    perm["pickUpItem"]   = &pickUpItem;
    perm["placeBlock"]   = &placeBlock;
}
LandPerm::LandPerm(const long& landId, const mce::UUID& uuid) : LandPerm() {
    reLandPerm(landId,uuid);
}
void LandPerm::reLandPerm(const long& landId, const mce::UUID& uuid) {
    if(XLand::isOwner(landId, uuid)) { //领地主，全权限
        for (auto& pair : perm) *pair.second = true;
        useItems   = {"all"};
        useBlocks  = {"all"};
        useEntitys = {"all"};
        return;
    }
    
    try { //不是主人，查询权限  如果没有就会使用默认权限，user=0时，为领地主设置的默认权限
        string sql = fmt::format("SELECT * FROM perm WHERE LID = {} AND (user = '{}' OR user = '0') ORDER BY user DESC",landId,uuid.asString());
        SQLite::Statement get{*XLand::db,sql};
        int num = get.getColumnCount();
        if (get.executeStep()) {
            useItems.clear(); useBlocks.clear(); useEntitys.clear();
            for (int i = 2; i < num; i++) {
                auto key = get.getColumnName(i);
                auto value = get.getColumn(i);
                if (value.isInteger()) {
                    *perm[key] = value.getInt();
                } else if(value.isText()) {
                    string item;
                    auto stream = stringstream(value.getString());
                    if     (!strcmp(key,"useItems"  )) while(getline(stream, item, ','))   useItems.push_back(item);
                    else if(!strcmp(key,"useBlocks" )) while(getline(stream, item, ','))  useBlocks.push_back(item);
                    else if(!strcmp(key,"useEntitys")) while(getline(stream, item, ',')) useEntitys.push_back(item);
                }
            }
            return;
        }
        get.clearBindings();
    } catch (std::exception const &e) {cerr << "error: " << e.what() << endl;}
    //没有找到权限表，使用默认权限  （暂时默认全无权限）
    for (auto& pair : perm) *pair.second = false;
    useItems.clear();
    useBlocks.clear();
    useEntitys.clear();
}
nlohmann::json LandPerm::getJson() {
    nlohmann::json pack;
    pack["placeBlock"  ] = placeBlock;
    pack["destroyBlock"] = destroyBlock;
    pack["pickUpItem"  ] = pickUpItem;
    pack["playerAttac" ] = playerAttac;
    pack["useItems"    ] = getArrStr(useItems);
    pack["useBlocks"   ] = getArrStr(useBlocks);
    pack["useEntitys"  ] = getArrStr(useEntitys);
    return pack;
}
// string getStr();

//class PlayerDate
map<mce::UUID, PlayerDate*> PlayerDate::playerDate = {};

PlayerDate::PlayerDate() {}
PlayerDate* PlayerDate::getPlayerDate(mce::UUID uuid) {
    return playerDate[uuid];
}
/**
 * @return code
 0: 
 1: 附近有其他领地主子
 2: 已选择点1: {} ,选点模式{}\n请继续选择点2
 3: 已选择点2: {} ,选点模式{}\n请继续选择领地点
 4: 请在领地范围内选择
 5: 已选领地位置: {} \n继续则重新选择点1
 **/
int PlayerDate::setPt(const Vec3& pos, int pt = 0) {
    if(XLand::hasLandIntersection(pos-10, pos+10)) return 1;
    if(pt == 0){
        pt = occupyPtindex % 3 + 1;
        occupyPtindex++;
    }
    int retu = 0;
    switch (pt) {
        case 1: 
            occupyPt1 = pos;
            landpos   = 0;
            retu      = 2;
            if(occupyPt1 != 0 && occupyPt2 != 0) occupyPt2 = occupyPt1;
            break;
        case 2: 
            occupyPt2 = pos;
            retu      = 3;
            landpos   = 0;
            toMaxMin(this->occupyPt1, this->occupyPt2);
            break;
        case 3: 
            auto max = this->occupyPt1;
            auto min = this->occupyPt2;
            if(min.x > pos.x || min.y > pos.y || min.z > pos.z || max.x < pos.x || max.y < pos.y || max.z < pos.z) {
                occupyPtindex = occupyPtindex ? occupyPtindex-1 : 0;
                retu = 4;
                break;
            }
            landpos = pos;
            retu = 5;
    }
    
    reBorder();
    return retu;
}
bool PlayerDate::reOccpyMode() {
    if(isOccupying) {
        isOccupying = false;
        occupyPtindex = 0;
        occupyPt1 = 0;
        occupyPt2 = 0;
    } else {
        isOccupying = true;
    }
    return isOccupying;
}

void PlayerDate::reBorder(int dimId, enum ParticleCUI::ColorPalette color) {
    ParticleCUI particleCUI;
    particleCUI.drawCuboid(AABB(occupyPt2 == 0 ? occupyPt1 : occupyPt2, occupyPt1+1),dimId,color);
}